use std::collections::*;

use super::model;
use crate::message::{MsgHandlerImpl, MsgTyId};

#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct BlkId(u16);

impl BlkId {
    pub fn zero() -> Self {
        Self(0)
    }

    pub fn is_zero(self) -> bool {
        self.0 == 0
    }
}

impl From<u16> for BlkId {
    fn from(value: u16) -> Self {
        Self(value)
    }
}

impl Into<u16> for BlkId {
    fn into(self) -> u16 {
        self.0
    }
}

/// Describes a kind of block.
pub struct BlockData {
    debug_name: String,
    behaviors: HashMap<MsgTyId, MsgHandlerImpl>,
    model: model::BlockModel,
}

impl BlockData {
    pub fn new(
        debug_name: String,
        behaviors: HashMap<MsgTyId, MsgHandlerImpl>,
        model: model::BlockModel,
    ) -> Self {
        Self {
            debug_name,
            behaviors,
            model,
        }
    }

    pub fn new_simple<S: ToString>(debug_name: S, model: model::BlockModel) -> Self {
        Self::new(debug_name.to_string(), HashMap::new(), model)
    }

    pub fn debug_name(&self) -> &str {
        &self.debug_name
    }

    /// Returns the message handler for the given message type.  If this return
    /// `None` then there is no message handler and typically the message should
    /// just be dropped.
    pub fn get_msg_handler_impl(&self, id: MsgTyId) -> Option<&MsgHandlerImpl> {
        self.behaviors.get(&id)
    }

    pub fn model(&self) -> &model::BlockModel {
        &self.model
    }

    pub fn solidity(&self) -> model::Solidity {
        self.model().solidity()
    }
}

/// Registration in a block registry.
pub struct BlockReg {
    ty: BlockData,
}

impl BlockReg {
    pub fn tydata(&self) -> &BlockData {
        &self.ty
    }
}

impl From<BlockData> for BlockReg {
    fn from(value: BlockData) -> Self {
        Self { ty: value }
    }
}
